//{=================================================================================
//! @file    stack.cpp
//! @date    2014-11-01 23:01
//! @author  Vladimir Gurinovich <whistleVG@gmail.com>
//!
//! 
//!
//! @par    Реализация стека с диагностикой ошибок 
//!           
//!
//}=================================================================================

#ifdef CLIENT_SIDE
#define DBG printf("#"),
#else
#define DBG if(0)
#endif // CLIENT_SIDE

#define ASSERTION(cond) ((cond)?:printf("YOU CANNOT DO THIS OPERATION WITH 1 NUMBER\n"))


//!====================================================================================================
//!  POISON - яд 
//!====================================================================================================

const double POISON = 666;

struct stack_t
{
    int counter;
    int max_size;
    double* elements;
};
//!< overflow маленькими буквами , тк overflow большими задефайнено 

    enum s_errors { overflow , EMPTY_STACK , WRONG_POISON_INSIDE , WRONG_SIZE , WRONG_POISON_OUTSIDE , OK };

    s_errors TYPE_OF_STACKERR = OK;

//!====================================================================================================

    void Stack_Construct(stack_t* stack , int max_size);

    double Stack_Push(stack_t* stack , double value);

    double Stack_pop(stack_t* stack);

    void Stack_destruct(stack_t* stack);

    char* m_strerror(int errno);
    void m_printERROR(char* str);

    void Stack_dump(stack_t* stk , int Print_visible);
    int Stack_OK(stack_t* stack);

    #define VERIFIED if(Stack_OK(stack)) Stack_dump(stack , 0);

//!====================================================================================================


void Stack_Construct(stack_t* stack , int max_size )
{

    stack_t other_stack = {};

    *stack = other_stack;

    (*stack).max_size = max_size;

    (*stack).elements = (double*)calloc(max_size , sizeof(*(*stack).elements));

    for(int step = 0 ; step < max_size ; step++)
    {
        (*stack).elements[step] = POISON;
    }

    VERIFIED

}

double Stack_Push(stack_t* stack , double value )
{

    VERIFIED

    (*stack).elements[(*stack).counter] = value ;

//!  DBG printf("value : %lg\n" , (*stack).elements[(*stack).counter]);

    (*stack).counter++ ;

    VERIFIED

    return value;

}

double Stack_pop(stack_t* stack )
{

    VERIFIED

    double value = (*stack).elements[ (*stack).counter - 1 ];
    (*stack).elements[(*stack).counter - 1] = POISON;

    (*stack).counter--;

    VERIFIED

    return value;                                          
}

void Stack_destruct(stack_t* stack)
{

    VERIFIED

    free((*stack).elements);

    (*stack).elements = 0;

}

//!====================================================================================================

int Stack_OK(stack_t* stack)
{

    for(int step = 0 ;  step < (*stack).max_size ; step++)
    {

        if((*stack).elements[step] == POISON && step < (*stack).counter)
        {
            TYPE_OF_STACKERR = WRONG_POISON_INSIDE;
            return 1;
        }

        if((*stack).elements[step] != POISON && step >= (*stack).counter + 1)
        {
            TYPE_OF_STACKERR = WRONG_POISON_OUTSIDE;
            return 1;
        }

    }

    if((*stack).counter < 0 )
    {
        TYPE_OF_STACKERR = EMPTY_STACK;
        return 1;
    }

    if((*stack).counter > (*stack).max_size)
    {
        TYPE_OF_STACKERR = overflow;
        return 1;
    }

    if((*stack).max_size < 0)
    {
        TYPE_OF_STACKERR = WRONG_SIZE;
        return 1;
    }

    return 0;

}

void Stack_dump(stack_t* stack , int Print_visible) 
{

    switch(Stack_OK(stack))
    {

    case 1 :

        m_printERROR("WTF : ");

        DBG printf("Stack(SOMETHING WENT WRONG)\n");
        DBG printf("{\n\n");
        DBG printf("count = %d\n" , (*stack).counter);
        DBG printf("elements[%d] , adress[0x%p]\n\n", (*stack).max_size , (*stack).elements);

        for(int i = 0; i < (*stack).max_size; i++)
        {

            if(i <= (*stack).counter - 1)
            {
                printf("=inside= ");
            }
            DBG printf("[%d] = %g\n" , i , (*stack).elements[i]);

        }

        DBG printf("}");
        exit(EXIT_SUCCESS);

        break;


    case 0 :

        if(Print_visible == 1)
        {

        DBG printf("Stack(FINE)\n");
        DBG printf("{\n\n");
        DBG printf("count = %d\n" , (*stack).counter);
        DBG printf("elements[%d] , adress[0x%p]\n\n", (*stack).max_size , (*stack).elements);

        for(int i = 0; i < (*stack).max_size; i++)

        {

            if(i <= (*stack).counter - 1)
            {
                printf("=inside=");
            }

            DBG printf("[%d] = %lg\n" , i , (*stack).elements[i]);

        }

        DBG printf("}\n");

        }

        else

        break;

    }

}

//!======================================================================================================================

char* m_strerror(s_errors TYPE_OF_STACKERR)
{
    switch(TYPE_OF_STACKERR)
    {

    case overflow :                   return  "Stack is full, look diagnostics below\n\n";                                break;
    case EMPTY_STACK:                 return  "Stack is empty, look diagnostics below\n\n";                               break;
    case WRONG_SIZE:                  return  "Array has wrong size, look diagnostics below\n\n";                         break;
    case WRONG_POISON_INSIDE:         return  "Something is wrong with elements inside, look diagnostics below\n\n";      break;
    case WRONG_POISON_OUTSIDE:        return  "Something is wrong with elements outside, look diagnostics below\n\n" ;    break;
    case OK:                          return  " ";                                                                       break;
    default:                          return  "ERROR";                                                                    break;

    }

}

void m_printERROR(char* str)
{
    char* error = m_strerror(TYPE_OF_STACKERR);
    printf("%s%s" , str , error);
}

//!========================================================================================================================























































